<!--
 * @Author: 安安
 * @Date: 2021-07-05 15:58:09
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2021-08-29 23:45:00
 * @Description: 下拉刷新，上拉加载更多组件
 * @FilePath: /partner-h5-pro/src/components/sd-scroll-new/index.vue
-->
<template>
  <div class="container">
    <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
      <van-list
        v-model="loading"
        :immediate-check="immediateCheck"
        :finished="finished"
        @load="onLoad"
      >
        <slot></slot>

        <!-- 如果列表没数据 -->
        <div v-if="!loading && list.length <= 0" class="empty">
          <img src="@/assets/img/common/pic_nothing@2x.png" />
          <p>没有数据</p>
        </div>

        <div v-if="loading" class="loading-txt"
          ><van-loading size="24px">上拉加载中...</van-loading></div
        >
        <template #finished
          ><span v-if="list.length > 0 && isMorePage">没有更多数据了</span></template
        >
      </van-list>
    </van-pull-refresh>
  </div>
</template>
<script lang="ts">
  import { defineComponent, reactive, toRefs, watch } from 'vue'

  interface Mystate {
    finished: boolean // 是否已加载完成，加载完成后不再触发load事件
    refreshing: boolean // 是否处于下拉加载中状态
    loading: boolean // 是否处于上拉加载状态，加载过程中不触发load事件
    error: boolean
  }

  interface Params {
    [key: string]: any
  }

  export default defineComponent({
    props: {
      // 是否在初始化时立即执行滚动位置检查
      immediateCheck: {
        type: Boolean,
        default: true
      },
      // 是否有翻页
      isMorePage: {
        type: Boolean,
        default: true
      },
      // 是否参数一变，就重新获取接口，不需要手动刷新页面，在list内的值不变的情况下可以用
      isWatchParams: {
        type: Boolean,
        default: true
      },
      // 列表请求方法
      api: {
        type: Function,
        default: () => ({})
      },
      // 请求的参数
      params: {
        type: Object,
        // eslint-disable-next-line vue/require-valid-default-prop
        default: {}
      },
      // 数据
      list: {
        type: Array,
        default: () => []
      }
    },
    emits: ['getData'],
    setup(props, { emit }) {
      const size = 10
      let page = 1
      let total = 0
      let isLoadingData = false // 是否能获取信息

      let list: any[] = []
      const state = reactive<Mystate>({
        finished: false,
        refreshing: false,
        loading: false,
        error: false
      })

      // 下拉刷新
      const onRefresh = () => {
        page = 1 // 重置翻页数
        state.refreshing = true
        state.finished = false // 重置可上拉判断
        onLoad() // 加载数据
      }

      // 上拉加载更多
      const onLoad = async () => {
        state.loading = state.refreshing ? false : true
        if (!isLoadingData) {
          // 如果正在获取数据，那么不允许再调用接口
          isLoadingData = true
          let params: Params | null = {}
          if (props.isMorePage) {
            params = { page, size, ...props.params }
          } else {
            params = Object.keys(props.params).length > 0 ? props.params : null
          }
          const res: any = params ? await props.api(params) : await props.api()

          if (res && res.ec === 200) {
            let _list: any[] = res.data.list || res.data
            if (props.isMorePage) {
              total = res.data.count || res.data.total
            } else {
              total = _list.length
            }
            if (page > 1) {
              _list = [...list, ..._list]
            }
            list = [..._list]

            emit('getData', { list: _list, total: total, res: res })
            if (list.length >= total) {
              state.finished = true
            }
            ++page // 页数+1
          } else {
            state.error = true
          }
          state.refreshing = false // 获取数据后，刷新状态结束
          state.loading = false // 状态改为可再次获取数据
          isLoadingData = false
        }
      }

      const reset = () => {
        const container = document.querySelector('.container')
        if (container) {
          container.scrollTop = 0 // 滚动到顶部
        }
        onRefresh() // 刷新接口
      }

      if (props.isWatchParams) {
        watch(props.params, () => {
          reset()
        })
      }

      return { ...toRefs(state), onRefresh, onLoad, reset }
    }
  })
</script>
<style lang="less" scoped>
  .loading-txt {
    color: #969799;
    font-size: 14px;
    line-height: 49px;
    text-align: center;
  }
  .empty {
    width: 100%;
    height: 100%;
    padding: 32px 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    img {
      width: 100%;
      height: auto;
    }

    p {
      margin-top: 16px;
      padding: 0 60px;
      color: #969799;
      font-size: 14px;
      line-height: 20px;
    }
  }
</style>
